package wypozyczalnia.mbeans;

import java.io.ByteArrayInputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;
import org.primefaces.model.UploadedFile;
import org.springframework.security.core.context.SecurityContextHolder;

import wypozyczalnia.domain.Genre;
import wypozyczalnia.domain.Hire;
import wypozyczalnia.domain.Movie;
import wypozyczalnia.domain.Photo;
import wypozyczalnia.domain.User;
import wypozyczalnia.forms.EditMovieForm;
import wypozyczalnia.service.GenreService;
import wypozyczalnia.service.HireService;
import wypozyczalnia.service.PhotoService;
import wypozyczalnia.service.UserService;
//import wypozyczalnia.forms.EditPersonForm;
import wypozyczalnia.service.MovieService;

@ManagedBean(name = "movieMBean")
@SessionScoped
public class MovieBean implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private List<Movie> movies;
	private Movie selectedMovie;
	private EditMovieForm editMovieForm = null;
	private List<Genre> genres;
	private List<String> selectedGenres;
	private String searchedMovie;
	private List<String> listImages;
	private Map<String, UploadedFile> uploadedFiles;
	private Hire hire;

	@ManagedProperty("#{movieService}")
	private MovieService movieService;

	@ManagedProperty("#{genreService}")
	private GenreService genreService;

	@ManagedProperty("#{photoService}")
	private PhotoService photoService;

	public List<Movie> getMovies() {
		this.movies = new ArrayList();
		this.movies = this.movieService.getAllMovies();
		return this.movies;
	}

	public void setMovies(List<Movie> movies) {
		this.movies = movies;
	}

	public List<Genre> getGenres() {
		this.genres = new ArrayList();
		this.genres = this.genreService.getAllGenres();
		return this.genres;
	}

	public void setGenres(List<Genre> genres) {
		this.genres = genres;
	}

	public GenreService getGenreService() {
		return this.genreService;
	}

	public void setGenreService(GenreService genreService) {
		this.genreService = genreService;
	}

	public Movie getSelectedMovie() {
		return this.selectedMovie;
	}

	public void setSelectedMovie(Movie selectedMovie) {
		this.selectedMovie = selectedMovie;
	}

	public MovieService getMovieService() {
		return this.movieService;
	}

	public void setMovieService(MovieService movieService) {
		this.movieService = movieService;
	}

	public EditMovieForm getEditMovieForm() {
		if (this.editMovieForm == null) {
			this.editMovieForm = new EditMovieForm();
		}
		return this.editMovieForm;
	}

	public void setEditMovieForm(EditMovieForm editMovieForm) {
		this.editMovieForm = editMovieForm;
	}

	public String dolistMovie() {
		return "listMovie";
	}

	public String listMovie() {
		return null;
	}

	public String doAddMovie() {
		this.selectedMovie = new Movie();
		this.listImages = null;
		this.uploadedFiles = null;
		this.selectedGenres = null;
		return "addMovie";
	}

	public String addMovie() {
		this.selectedMovie.setGenre(this.genreService
				.getGenresByIds(this.selectedGenres));

		this.selectedMovie.setAvailable(Boolean.valueOf(true));

		this.movieService.addMovie(this.selectedMovie);
		List photos = new ArrayList();
		if (this.listImages != null) {
			for (String key : this.listImages) {
				Photo p = new Photo();
				UploadedFile f = (UploadedFile) this.uploadedFiles.get(key);
				p.setMainPhoto(Boolean.valueOf(true));
				p.setPhoto(f.getContents());
				photos.add(p);
				p.setMovie(this.selectedMovie);
			}
		}

		this.photoService.addPhotos(photos);
		this.selectedMovie.setPhotos(photos);
		FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
				"Sukces: ", "Dodano film");

		FacesContext.getCurrentInstance().addMessage(null, message);

		return "listMovie";
	}

	public String editMovie() {
		ExternalContext externalContext = FacesContext.getCurrentInstance()
				.getExternalContext();

		String movieId = (String) externalContext.getRequestParameterMap().get(
				"movieId");

		this.selectedMovie = this.movieService.getMovieById(Integer
				.valueOf(Integer.parseInt(movieId)));
		selectedGenres = new ArrayList<String>();
		for (Genre g : selectedMovie.getGenre()) {
			selectedGenres.add(g.getIdGenre().toString());
		}
		this.listImages = new ArrayList();
		this.uploadedFiles = new HashMap();

		return "editMovie";
	}

	public String saveEditedMovie() {
		List<Photo> photos = new ArrayList();
		if (this.listImages != null) {
			for (String key : this.listImages) {
				Photo p = new Photo();
				UploadedFile f = (UploadedFile) this.uploadedFiles.get(key);
				p.setMainPhoto(Boolean.valueOf(true));
				p.setPhoto(f.getContents());
				photos.add(p);
				p.setMovie(this.selectedMovie);
			}
		}
		if (!photos.isEmpty()) {
			this.photoService.addPhotos(photos);
			if (selectedMovie.getPhotos() == null) {
				selectedMovie.setPhotos(photos);
			} else {
				this.selectedMovie.getPhotos().addAll(photos);
			}
		}
		this.selectedMovie.setGenre(this.genreService
				.getGenresByIds(this.selectedGenres));
		this.movieService.updateMovie(this.selectedMovie);
		FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
				"Sukces: ", "Zedytowano film");

		FacesContext.getCurrentInstance().addMessage(null, message);

		return null;
	}

	public String deleteActualPhoto() {
		ExternalContext externalContext = FacesContext.getCurrentInstance()
				.getExternalContext();

		String imageId = (String) externalContext.getRequestParameterMap().get(
				"imageIdD");

		photoService.deleteById(Integer.parseInt(imageId));
		int i = 0;
		for (Photo p : selectedMovie.getPhotos()) {
			if (p.getIdPhoto().toString().equals(imageId)) {
				break;
			}
			i++;
		}
		selectedMovie.getPhotos().remove(i);
		FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
				"Sukces: ", "Usunięto obraz");

		FacesContext.getCurrentInstance().addMessage(null, message);

		return "";
	}

	public String deletePhoto() {
		ExternalContext externalContext = FacesContext.getCurrentInstance()
				.getExternalContext();

		String imageId = (String) externalContext.getRequestParameterMap().get(
				"imageId");
		uploadedFiles.remove(imageId);
		listImages.remove(imageId);
		FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
				"Sukces: ", "Usunięto obraz z listy");

		FacesContext.getCurrentInstance().addMessage(null, message);

		return "";

	}

	public String showMovie() {
		ExternalContext externalContext = FacesContext.getCurrentInstance()
				.getExternalContext();

		String movieId = (String) externalContext.getRequestParameterMap().get(
				"movieId");

		this.selectedMovie = this.movieService.getMovieById(Integer
				.valueOf(Integer.parseInt(movieId)));

		return "showMovie";
	}

	@ManagedProperty("#{userService}")
	private UserService userService;

	@ManagedProperty("#{hireService}")
	private HireService hireService;

	public String doHireMovie() {
		hire = new Hire();
		hire.setStartDate(new Date());
		hire.setMovie(selectedMovie);
		String username = SecurityContextHolder.getContext()
				.getAuthentication().getName();
		User loggedUser = this.userService.getUserByUsername(username);
		hire.setUser(loggedUser);

		return "hireMovie";
	}

	public String goToHiredList() {

		return "hiredMovies";
	}

	public String unhireMovie() {
		Hire h = selectedMovie.getActiveHire();
		h.setCancel(true);
		hireService.update(h);
		FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
				"Sukces: ", "Film oznaczony jako niewypożyczony.");

		FacesContext.getCurrentInstance().addMessage(null, message);
		return "";
	}

	public List<Hire> getHiredList() {
		String username = SecurityContextHolder.getContext()
				.getAuthentication().getName();
		User loggedUser = this.userService.getUserByUsername(username);
		return hireService.getHiresForUser(loggedUser);
	}

	public String hireMovie() {
		if (selectedMovie.isMovieHired()) {
			FacesMessage message = new FacesMessage(
					FacesMessage.SEVERITY_ERROR, "Błąd: ",
					"Film jest aktualnie wypożyczony");

			FacesContext.getCurrentInstance().addMessage(null, message);
			return null;
		}
		long tenDays = 86400000 * 10;

		hire.setCancel(false);
		if (hire.getStartDate().getTime() > hire.getEndDate().getTime()) {
			FacesMessage message = new FacesMessage(
					FacesMessage.SEVERITY_ERROR, "Błąd: ",
					"Data do, musi być późniejsza niż data wypożyczenia.");

			FacesContext.getCurrentInstance().addMessage(null, message);
			return null;
		} else if (hire.getEndDate().getTime() > (hire.getStartDate().getTime() + tenDays)) {
			FacesMessage message = new FacesMessage(
					FacesMessage.SEVERITY_ERROR, "Błąd: ",
					"Data końca rezerwacji nie może przekraczać 10 dni od złożenia rezerwacji.");

			FacesContext.getCurrentInstance().addMessage(null, message);
			return null;
		}
		hireService.create(hire);

		return "hiredMovies";
	}

	public String doAddGenre() {
		return "addGenre";
	}

	public String addGenre() {
		this.movieService.createGenre(new Genre(this.editMovieForm.getGenre()));
		FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
				"Sukces: ", "dodano nowy gatunek: " + editMovieForm.getGenre());

		FacesContext.getCurrentInstance().addMessage(null, message);
		editMovieForm = new EditMovieForm();

		return null;
	}

	public List<String> getSelectedGenres() {
		return this.selectedGenres;
	}

	public void setSelectedGenres(List<String> selectedGenres) {
		this.selectedGenres = selectedGenres;
	}

	public List<String> complete(String query) {
		List<String> results = new ArrayList();
		List<Movie> allMovies = getMovies();
		for (Movie movie : allMovies) {
			if ((movie.getProduction().contains(query))
					|| (movie.getTitle().contains(query))) {
				results.add(movie.getTitle());
			}
		}

		return results;
	}

	public String getSearchedMovie() {
		return this.searchedMovie;
	}

	public void setSearchedMovie(String searchedMovie) {
		this.searchedMovie = searchedMovie;
	}

	public void doSearchMovie(ActionEvent action) {
		List result = this.movieService.getMovieByTitle(this.searchedMovie);
		if (result.size() > 0)
			setSelectedMovie((Movie) result.get(0));
	}

	public void upload(FileUploadEvent event) {
		FacesMessage msg = new FacesMessage("Success! ", event.getFile()
				.getFileName() + " is uploaded.");

		FacesContext.getCurrentInstance().addMessage(null, msg);
		UploadedFile file = event.getFile();
		String key = file.getFileName();
		if (this.uploadedFiles == null) {
			this.uploadedFiles = new HashMap();
		}
		this.uploadedFiles.put(key, file);
		if (this.listImages == null) {
			this.listImages = new ArrayList();
		}
		this.listImages.add(key.toString());
	}

	public StreamedContent getImage() {
		ExternalContext externalContext = FacesContext.getCurrentInstance()
				.getExternalContext();

		if (FacesContext.getCurrentInstance().getRenderResponse()) {
			// So, we're rendering the view. Return a stub StreamedContent so
			// that it will generate right URL.
			return new DefaultStreamedContent();
		} else {
			String imageId = (String) externalContext.getRequestParameterMap()
					.get("imageIdD");
			Photo p = null;
			if (selectedMovie.getPhotos() != null) {
				for (Photo photo : selectedMovie.getPhotos()) {
					if (photo.getIdPhoto().toString().equals(imageId)) {
						p = photo;
					}
				}
			}
			StreamedContent image = null;
			if (p != null) {
				image = new DefaultStreamedContent(new ByteArrayInputStream(
						p.getPhoto()), "image/png");

				return image;
			}
		}

		return null;
	}

	public List<String> getListImages() {
		return this.listImages;
	}

	public void setListImages(List<String> listImages) {
		this.listImages = listImages;
	}

	public Map<String, UploadedFile> getUploadedFiles() {
		return this.uploadedFiles;
	}

	public void setUploadedFiles(Map<String, UploadedFile> uploadedFiles) {
		this.uploadedFiles = uploadedFiles;
	}

	public void setPhotoService(PhotoService photoService) {
		this.photoService = photoService;
	}

	public Hire getHire() {
		return hire;
	}

	public void setHire(Hire hire) {
		this.hire = hire;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public HireService getHireService() {
		return hireService;
	}

	public void setHireService(HireService hireService) {
		this.hireService = hireService;
	}
}
